<?php
/**
 *
 * @author Zeon <scplay@gmail.com>
 * @date 2018/7/26
 * @copyright PanxSoft Inc.
 */
namespace App\Exceptions;

use App\Services\Utils\FormatLog;
use App\Services\Utils\IpUtils;

class ApiException extends ApiAbstractException
{
    /**
     * @var array - 可通过 Admin Error Code 让 Laravel 不 Log 如一些轮询的抛错
     */
    protected $silent_err_codes = [
        ApiErrCode::APP_LOGIN_SCAN_EVT_NOT_FOUND,
        ApiErrCode::APP_STAFF_SCAN_EVT_NOT_FOUND,
        ApiErrCode::APP_FAVORS_SCAN_EVT_NOT_FOUND,
        ApiErrCode::WX_SESSION_OPENID_NOT_FOUND,
    ];

    /**
     * ApiException constructor.
     *
     * @param int $code
     * @param string $error
     * @param bool $debug
     *
     * @throws ApiSilentException
     */
    public function __construct(int $code = ApiErrCode::UNKNOWN_ERROR,
                                string $error = parent::UNKNOWN_MSG,
                                bool $debug = false)
    {
        parent::__construct($code, $error, $debug);

        // should after $this->code / error / debug assignment
        $this->checkThrowSilentException();
    }

    /**
     * if need silent don't report
     *
     * @throws ApiSilentException
     */
    private function checkThrowSilentException(): void
    {
        $should_silent = in_array($this->code, $this->silent_err_codes);
        if ($should_silent) {
            throw new ApiSilentException($this->code, $this->error, $this->debug);
        }
    }

    /**
     * 只 log 错误信息 (错误码) + 调用位置
     */
    public function report()
    {
        $last_trace_str = $this->getLastTraceStr();
        $br = PHP_EOL;
        $request_log = FormatLog::request();

        $log = "{$this->error}({$this->code}) {$br}{$request_log} {$br}{$last_trace_str}";

        logger()->error($log);

        /** @var array|string $req - hack for log error type hint need string */
        $req = request()->all();
        if ($req) {
            logger()->error($req);
        }
    }

    /**
     * @return string
     */
    private function getLastTraceStr(): string
    {
        $trace_str = $this->getTraceAsString();

        $last_trace_str = strtok($trace_str, "\n");

        return $last_trace_str;
    }
}